package org.doc.core.api.springmvc;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.doc.bean.Api;
import org.doc.bean.ApiAction;
import org.doc.bean.ApiRequestParam;
import org.doc.bean.ApiResponseParam;
import org.doc.core.api.AbstractApiParser;
import org.doc.core.config.DocConfig;
import org.doc.core.constant.Constant;
import org.doc.core.exception.RestfulDocException;
import org.doc.utils.ClassUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.Tag;

public class SpringMVCApiParser extends AbstractApiParser {

    @Override
    public List<String> filterController(List<String> fileNames) {

        List<String> controllerFileNames = new ArrayList<String>();

        for (String fileName : fileNames) {
            String packageFileName = fileName.substring(Constant.JAVA_FILE_PATH.length(), fileName.length() - Constant.JAVA_FILE_SUFFIX.length()).replace(File.separator, ".");
            try {
                Class<?> fileClass = Class.forName(packageFileName);
                Controller controller = fileClass.getAnnotation(Controller.class);
                RestController restController = fileClass.getAnnotation(RestController.class);
                if (controller != null || restController != null) {
                    controllerFileNames.add(fileName);
                }
            } catch (ClassNotFoundException e) {

            }
        }
        return controllerFileNames;
    }

    @Override
    public List<Api> generateApi(ClassDoc[] classDocs) {

        List<Api> apis = new ArrayList<Api>();
        String prefix = DocConfig.getValue("api.prefix");
        if(prefix ==null || prefix.trim().length()<1){
        	prefix="";
        }
        
        for (ClassDoc classDoc : classDocs) {

            Api api = new Api();
            //controller类上面有@title注释，则作为标题，否则使用普通文本注释，
            Tag[] tag = classDoc.tags("title");
            if(tag.length>0){
            	api.setTitle(tag[0].text());
            }else{
            	api.setTitle(classDoc.commentText());
            }
           // api.setTitle(classDoc.com);

            MethodDoc[] methodDocs = classDoc.methods(false);

            Class<?> controllerClass = null;
            try {
                controllerClass = Class.forName(classDoc.qualifiedTypeName());
            } catch (ClassNotFoundException e) {

            }

            RequestMapping controllerRequestMapping = controllerClass.getAnnotation(RequestMapping.class);

            String url = "";
            if (controllerRequestMapping != null) {
                url = controllerRequestMapping.value()[0];
                url = prefix+url;
                /*try {
					url = url.replace("{version}", version);
				} catch (Exception e) {
					System.out.println("***请在配置文件中添加api.version属性，如 api.version=v2 ***");
					e.printStackTrace();
				}*/
            }

            List<ApiAction> apiActions = new ArrayList<ApiAction>(methodDocs.length);

            for (MethodDoc methodDoc : methodDocs) {
            	//以#DOC#开头的注释才进行转换
            	String comment = methodDoc.commentText();
            	if(comment !=null && comment.length()>0){
            		String[] strArr = comment.split("\n");
            		if(strArr.length > 0 && strArr[0].trim().startsWith("#DOC#")){
            			comment = comment.substring(5, comment.length());
            		}else{
            			continue;
            		}
            	}else{
            		continue;
            	}

                ApiAction apiAction = new ApiAction();

                Class<?>[] paramTypes = null;
                Method method = null;
                try {
                    paramTypes = ClassUtils.getParamTypes(methodDoc);
                    method = controllerClass.getDeclaredMethod(methodDoc.name(), paramTypes);
                } catch (Exception e) {

                }
                Tag[] tags = methodDoc.tags();

                List<ApiRequestParam> apiRequestParams = generateApiReqeustParam(tags);
                List<ApiResponseParam> apiResponseParams = generateApiResponseParam(tags);
                String title = getTitle(tags);
                String respBody = getRespBody(tags);
                String requestUrl = generateRequestUrl(method, url);
                String requestType = getRequestType(method);

                apiAction.setRequestType(requestType);
                apiAction.setTitle(title);
                apiAction.setRespText(respBody);
                apiAction.setRespParams(apiResponseParams);
                apiAction.setReqParams(apiRequestParams);
                apiAction.setUrl(requestUrl);
                apiAction.setDesc(comment);
                apiActions.add(apiAction);
            }
            if(apiActions.size()>0){
            	api.setApiActions(apiActions);
                apis.add(api);
            }
            
        }
        return apis;

    }

    private String generateRequestUrl(Method method, String url) {
        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
        if (requestMapping == null) {
            throw new RestfulDocException("please add requestMapping annotion on this method " + method.getName());
        }
        return url + requestMapping.value()[0];
    }

    private String getRequestType(Method method) {
        StringBuilder requestType = new StringBuilder();
        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
        RequestMethod[] requestMethods = requestMapping.method();
        if (requestMethods != null) {
            for (int i = 0; i < requestMethods.length; i++) {
                if (RequestMethod.GET == requestMethods[i]) {
                    requestType.append(Constant.GET).append(",");
                }

                if (RequestMethod.POST == requestMethods[i]) {
                    requestType.append(Constant.POST).append(",");
                }
            }
        }
        if (requestType.length() > 0) {
            return requestType.substring(0, requestType.length() - 1);
        }
        
        return Constant.POST+","+Constant.GET;
    }

}
